# -*- coding: utf-8 -*-
#
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

"""类型收窄分析

提供类型收窄的核心数据结构和分析功能
"""

from dataclasses import dataclass, field
from typing import Optional, Dict
from mcpy.symbol_meta import TypeInfo


@dataclass
class TypeNarrowingInfo:
    """类型收窄信息
    
    记录变量在特定作用域内的类型收窄
    
    Attributes:
        var_name: 变量名
        original_type: 原始类型（如 Optional[int]）
        narrowed_type: 收窄后的类型（如 int）
        narrowing_kind: 收窄类型（"optional_unwrap", "isinstance", "union_discriminate", "any_cast"）
    
    Examples:
        >>> # Optional[int] 收窄为 int
        >>> info = TypeNarrowingInfo(
        ...     var_name="num",
        ...     original_type=TypeInfo(name="Optional", args=[TypeInfo(name="int")]),
        ...     narrowed_type=TypeInfo(name="int"),
        ...     narrowing_kind="optional_unwrap"
        ... )
    """
    var_name: str
    original_type: TypeInfo
    narrowed_type: TypeInfo
    narrowing_kind: str  # "optional_unwrap", "isinstance", "union_discriminate", "any_cast", "wrapper_unwrap"
    
    def __repr__(self) -> str:
        """可读的字符串表示"""
        return (
            f"TypeNarrowingInfo(var_name='{self.var_name}', "
            f"{self.original_type.name} -> {self.narrowed_type.name}, "
            f"kind='{self.narrowing_kind}')"
        )


@dataclass
class WrapperTypeConfig:
    """包装类型配置
    
    从 builtin 配置或 stub 文件中加载的包装类型元信息
    
    Attributes:
        type_name: 类型名称（如 "Optional[T]", "unique_ptr[T]"）
        is_wrapper: 是否是包装类型
        inner_type: 内部类型（如 "T"）
        cpp_type: C++ 类型映射（如 "std::optional<T>"）
        includes: 需要包含的头文件
        unwrap_strategies: 解包策略列表
        truthiness_check: 真值检查模板
        source: 配置来源（"builtin" 或 "stub"）
    """
    type_name: str
    is_wrapper: bool
    inner_type: str
    cpp_type: str
    includes: list[str] = field(default_factory=list)
    unwrap_strategies: list[dict] = field(default_factory=list)
    truthiness_check: Optional[str] = None
    source: str = "builtin"  # "builtin" 或 "stub"
    
    def get_unwrap_strategy(self, context: str = "always") -> Optional[dict]:
        """获取匹配的解包策略
        
        Args:
            context: 使用上下文（"value_context", "member_access", "always"）
        
        Returns:
            匹配的策略配置，如果没有则返回 None
        """
        for strategy in self.unwrap_strategies:
            condition = strategy.get("condition", "always")
            if condition == context or condition == "always":
                return strategy
        
        # 如果没有精确匹配，返回第一个 "always" 策略
        for strategy in self.unwrap_strategies:
            if strategy.get("condition") == "always":
                return strategy
        
        return None


class WrapperTypeRegistry:
    """包装类型注册表
    
    管理来自 builtin 配置和 stub 扩展的包装类型元信息
    
    职责：
    1. 从 builtin 配置加载标准库类型
    2. 从 stub 文件加载用户自定义类型
    3. 提供类型查询接口
    4. 管理配置优先级（用户 stub > 系统 stub > builtin）
    
    Examples:
        >>> registry = WrapperTypeRegistry()
        >>> optional_type = TypeInfo(name="Optional", args=[TypeInfo(name="int")])
        >>> 
        >>> # 检查是否是包装类型
        >>> registry.is_wrapper_type(optional_type)
        True
        >>> 
        >>> # 获取内部类型
        >>> inner = registry.get_inner_type(optional_type)
        >>> inner.name
        'int'
        >>> 
        >>> # 获取解包策略
        >>> strategy = registry.get_unwrap_strategy(optional_type, "value_context")
        >>> strategy["pattern"]
        '{self}.value()'
    """
    
    def __init__(self):
        """初始化注册表"""
        self._wrapper_configs: Dict[str, WrapperTypeConfig] = {}
        self._load_builtin_configs()
        # TODO: 实现 stub 加载
        # self._load_stub_configs()
    
    def _load_builtin_configs(self):
        """从 builtin 配置加载标准库类型"""
        from mcpy.builtin.builtin_table import BUILTIN_CONFIG
        
        for type_name, config in BUILTIN_CONFIG.items():
            wrapper_info = config.get("wrapper_info")
            if wrapper_info and wrapper_info.get("is_wrapper"):
                # 将 builtin 配置转换为 WrapperTypeConfig
                wrapper_config = WrapperTypeConfig(
                    type_name=type_name,
                    is_wrapper=True,
                    inner_type=wrapper_info.get("inner_type", "T"),
                    cpp_type=config.get("cpp_type", type_name),
                    includes=config.get("includes", []),
                    unwrap_strategies=wrapper_info.get("unwrap_strategies", []),
                    truthiness_check=wrapper_info.get("truthiness_check"),
                    source="builtin"
                )
                self._wrapper_configs[type_name] = wrapper_config
    
    def _load_stub_configs(self):
        """从 stub 文件加载用户自定义类型
        
        TODO: 实现 stub 文件解析
        查找所有 .pyi 文件中的 __mcpy_wrapper_info__ 属性
        """
        # 预留实现
        pass
    
    def is_wrapper_type(self, type_info: Optional[TypeInfo]) -> bool:
        """检查是否是包装类型
        
        Args:
            type_info: 类型信息
        
        Returns:
            是否是包装类型
        """
        if not type_info:
            return False
        
        base_name = self._get_base_name(type_info)
        return base_name in self._wrapper_configs
    
    def get_wrapper_config(self, type_info: TypeInfo) -> Optional[WrapperTypeConfig]:
        """获取包装类型配置
        
        Args:
            type_info: 类型信息
        
        Returns:
            包装类型配置，如果不是包装类型则返回 None
        """
        base_name = self._get_base_name(type_info)
        return self._wrapper_configs.get(base_name)
    
    def get_inner_type(self, type_info: TypeInfo) -> Optional[TypeInfo]:
        """获取包装类型的内部类型
        
        例如：Optional[int] -> int
              unique_ptr[User] -> User
        
        Args:
            type_info: 包装类型信息
        
        Returns:
            内部类型，如果无法提取则返回 None
        """
        if not self.is_wrapper_type(type_info):
            return None
        
        # 如果是泛型类型，提取第一个类型参数
        from mcpy.symbol_meta import TypeKind
        if type_info.kind == TypeKind.GENERIC and type_info.args:
            return type_info.args[0]
        
        return None
    
    def get_unwrap_strategy(
        self, 
        type_info: TypeInfo, 
        context: str = "value_context"
    ) -> Optional[dict]:
        """获取解包策略
        
        Args:
            type_info: 包装类型
            context: 使用上下文（"value_context", "member_access", "always"）
        
        Returns:
            解包策略配置（包含 pattern 和 precedence），如果没有则返回 None
        """
        wrapper_config = self.get_wrapper_config(type_info)
        if not wrapper_config:
            return None
        
        return wrapper_config.get_unwrap_strategy(context)
    
    def get_truthiness_check(self, type_info: TypeInfo) -> Optional[str]:
        """获取真值检查模板
        
        用于生成 if 语句的条件表达式
        
        Args:
            type_info: 包装类型
        
        Returns:
            真值检查模板（如 "{self}.has_value()"），如果没有则返回 None
        """
        wrapper_config = self.get_wrapper_config(type_info)
        if not wrapper_config:
            return None
        
        return wrapper_config.truthiness_check
    
    def register_wrapper_type(self, config: WrapperTypeConfig):
        """动态注册包装类型
        
        用于从 stub 文件加载或运行时注册
        
        Args:
            config: 包装类型配置
        """
        self._wrapper_configs[config.type_name] = config
    
    def _get_base_name(self, type_info: TypeInfo) -> str:
        """获取类型的基础名称
        
        例如：Optional[int] -> Optional[T]
              unique_ptr[User] -> unique_ptr[T]
        
        Args:
            type_info: 类型信息
        
        Returns:
            基础名称
        """
        from mcpy.symbol_meta import TypeKind
        
        if type_info.kind == TypeKind.GENERIC:
            # 泛型类型，替换类型参数为 T
            return f"{type_info.name}[T]"
        return type_info.name


# 全局实例
_global_registry: Optional[WrapperTypeRegistry] = None


def get_wrapper_registry() -> WrapperTypeRegistry:
    """获取全局包装类型注册表
    
    单例模式，确保全局只有一个注册表实例
    
    Returns:
        全局包装类型注册表
    """
    global _global_registry
    if _global_registry is None:
        _global_registry = WrapperTypeRegistry()
    return _global_registry

